package com.snail.snailvr.network.providers.downloads;

import android.content.Context;
import android.database.Cursor;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.support.v4.util.LongSparseArray;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;

import com.activeandroid.query.Select;
import com.snail.snailvr.R;
import com.snail.snailvr.VRApp;
import com.snail.snailvr.event.BusProvider;
import com.snail.snailvr.model.TaskInfo;
import com.snail.snailvr.model.VideoInfo;
import com.snail.snailvr.utils.Constant;
import com.snail.snailvr.utils.FileUtil;
import com.snail.snailvr.utils.LogUtils;
import com.snail.snailvr.utils.NetworkUtil;
import com.snail.snailvr.utils.SharedPreferencesUtil;
import com.snail.snailvr.utils.ToastUtils;
import com.snail.snailvr.utils.Util;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

import rx.Observable;
import rx.Single;
import rx.SingleSubscriber;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * 下载辅助类
 * Created by snail on 16/4/15.
 */
public class DownloadHelper {
    public static final int DOWNLOAD_DEMO = 1, DOWNLOAD_FROM_LINK = 2, DOWNLOAD_From_LIST = 3, DOWNLOAD_FROM_UPDATE = 4;
    public static final int QUERY_TYPE_BY_STATUS = 1;
    public static final int QUERY_TYPE_BY_ID = 2;
    private static DownloadManager downloadManager = null;
    public static final String DEFAULT_DOWNLOAD_SPEED = "0KB";
    private static LongSparseArray<Long[]> downloadSpeedMap = new LongSparseArray();

    public static DownloadManager getDownloadManager() {
        synchronized (DownloadHelper.class) {
            if (downloadManager == null) {
                downloadManager = new DownloadManager(VRApp.getInstance().getContentResolver(), Constant.PACKAGE_NAME);
            }
            return downloadManager;
        }
    }

    /**
     * 根据查询条件，获取相应的下载任务信息
     */
    public static List<TaskInfo> getDownloadTasks(Context context, int queryType, int queryFilter) {

        List<TaskInfo> mDownloadTasks = new ArrayList<>();

        DownloadManager.Query query;
        switch (queryType) {
            case QUERY_TYPE_BY_ID:
                query = new DownloadManager.Query().setFilterById(queryFilter);
                break;
            case QUERY_TYPE_BY_STATUS:
                query = new DownloadManager.Query().setFilterByStatus(queryFilter);
                break;
            default:
                com.snailgame.fastdev.util.LogUtils.e("Invalid query type, Type=" + queryType);
                return mDownloadTasks;
        }

        Cursor cursor = getDownloadManager().query(query);
        if (cursor == null || cursor.isClosed())
            return mDownloadTasks;


        int taskId = cursor.getColumnIndex(DownloadManager.COLUMN_ID);
        int taskAppId = cursor.getColumnIndex(DownloadManager.COLUMN_APP_ID);
        int taskName = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TITLE);
        int taskUri = cursor.getColumnIndex(DownloadManager.COLUMN_URI);
        int taskDesc = cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
        int taskTotalSize = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
        int taskDownloadSize = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
        int taskLocalUri = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
        int taskStatus = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
        int reason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);

        while (cursor.moveToNext()) {
            TaskInfo taskInfo = new TaskInfo();
            taskInfo.setTaskId(cursor.getLong(taskId));
            int appId = cursor.getInt(taskAppId);

            taskInfo.setAppId(appId);
            taskInfo.setTaskName(cursor.getString(taskName));
            int status = cursor.getInt(taskStatus);
            taskInfo.setDownloadState(status);

            if (taskInfo.getDownloadState() == DownloadManager.STATUS_SUCCESSFUL) {
                try {
                    getDownloadManager().openDownloadedFile(taskInfo.getTaskId());
                } catch (FileNotFoundException e) {
                    getDownloadManager().remove(taskInfo.getTaskId());
                    continue;
                }
            }

            long downloadedSize = cursor.getLong(taskDownloadSize);
            taskInfo.setDownloadedSize(downloadedSize);

            long totalSize = cursor.getLong(taskTotalSize);

            taskInfo.setVideoTotalSize(totalSize);
            if (totalSize != 0)
                taskInfo.setTaskPercent((int) ((downloadedSize * 100) / totalSize));
            taskInfo.setDesc(cursor.getString(taskDesc));
            taskInfo.setVideoUri(cursor.getString(taskUri));
            taskInfo.setVideoLocalUri(cursor.getString(taskLocalUri));
            taskInfo.setReason(cursor.getInt(reason));
            mDownloadTasks.add(taskInfo);
        }
        if (!cursor.isClosed())
            cursor.close();
        return mDownloadTasks;
    }

    /**
     * 根据下载task 更改下载列表的数据
     *
     * @param videoInfoList
     */
    public static synchronized void updateDownloadState(final List<VideoInfo> videoInfoList
            , final RecyclerView.Adapter adapter) {
        if (videoInfoList == null || videoInfoList.isEmpty()) return;
        Observable.create(new Observable.OnSubscribe<TaskInfo>() {
            @Override
            public void call(Subscriber<? super TaskInfo> subscriber) {
                int queryFilter = DownloadManager.STATUS_RUNNING
                        | DownloadManager.STATUS_FAILED
                        | DownloadManager.STATUS_PAUSED
                        | DownloadManager.STATUS_PENDING
                        | DownloadManager.STATUS_SUCCESSFUL;

                List<TaskInfo> taskInfoList = DownloadHelper.getDownloadTasks(
                        VRApp.getInstance(),
                        DownloadHelper.QUERY_TYPE_BY_STATUS,
                        queryFilter);
                for (VideoInfo videoInfo : videoInfoList) {
                    for (TaskInfo taskInfo : taskInfoList) {
                        if (taskInfo.getTaskId() == videoInfo.getVideoId() || (videoInfo.getIBannerId() != 0 && taskInfo.getAppId() == videoInfo.getIBannerId())) {
                            videoInfo.setVideoId(taskInfo.getTaskId());
                            videoInfo.setVideoName(taskInfo.getTaskName());
                            videoInfo.setVideoSize(taskInfo.getVideoTotalSize());
                            videoInfo.setDownloadedSize(taskInfo.getDownloadedSize());
                            videoInfo.setDownloadedPercent(taskInfo.getTaskPercent());
                            videoInfo.setDownloadState(taskInfo.getDownloadState());


                            int reason = taskInfo.getReason();
                            videoInfo.setReason(reason);
                            break;
                        }
                    }
                }
                subscriber.onCompleted();
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<TaskInfo>() {
                    @Override
                    public void onCompleted() {
                        adapter.notifyDataSetChanged();
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(TaskInfo taskInfo) {


                    }
                });

    }

    /**
     * calculate the download speed of a specified task
     *
     * @param context
     * @param videoInfo
     * @param runningTask
     */
    public static void calcDownloadSpeed(Context context, VideoInfo videoInfo, TaskInfo runningTask) {
        int downloadState = runningTask.getDownloadState();
        if (downloadState == DownloadManager.STATUS_RUNNING) {
            if (downloadSpeedMap.get(runningTask.getTaskId()) == null) {
                Long[] speedArr = new Long[3];
                speedArr[0] = runningTask.getDownloadedSize();
                speedArr[1] = System.currentTimeMillis();
                speedArr[2] = 0L;
                downloadSpeedMap.put(runningTask.getTaskId(), speedArr);
                videoInfo.setDownloadSpeed(DEFAULT_DOWNLOAD_SPEED);
            } else {
                long oldDownloadedSize = downloadSpeedMap.get(runningTask.getTaskId())[0];
                long newDownloadedSize = runningTask.getDownloadedSize();
                long oldUpdateTime = downloadSpeedMap.get(runningTask.getTaskId())[1];
                long newUpdateTime = System.currentTimeMillis();
                long elapsedTime = newUpdateTime - oldUpdateTime > 0 ? (newUpdateTime - oldUpdateTime) : 1;
                long speed = 0;
                if (newDownloadedSize > oldDownloadedSize) {
                    speed = (long) (((newDownloadedSize - oldDownloadedSize) * 1000 / (elapsedTime)) * 0.98);
                    videoInfo.setDownloadSpeed(FileUtil.formatShortFileSize(context, speed)); // 0.98 = 1000/1024
                } else {
                    if (elapsedTime > 1000) {
                        videoInfo.setDownloadSpeed(DEFAULT_DOWNLOAD_SPEED);
                    } else {
                        speed = downloadSpeedMap.get(runningTask.getTaskId())[2];
                        videoInfo.setDownloadSpeed(FileUtil.formatShortFileSize(context, speed));
                    }
                }
                downloadSpeedMap.get(runningTask.getTaskId())[0] = newDownloadedSize;
                downloadSpeedMap.get(runningTask.getTaskId())[1] = newUpdateTime;
                downloadSpeedMap.get(runningTask.getTaskId())[2] = speed;
            }
        } else {
            videoInfo.setDownloadSpeed(DEFAULT_DOWNLOAD_SPEED);
            if (downloadState == DownloadManager.STATUS_SUCCESSFUL) {
                if (downloadSpeedMap.get(runningTask.getTaskId()) != null) {
                    downloadSpeedMap.remove(runningTask.getTaskId());
                }
            }
        }
    }

    /**
     * 处理暂停或者失败后的提示信息
     *
     * @param context
     * @param label   下载应用名称
     * @param state   下载的任务状态
     * @param reason  暂停或者是失败的原因
     */
    public static void handleMsgForPauseOrError(Context context, String label,
                                                int state, int reason) {
        int tipId = -1;
        LogUtils.d("status=" + state + "reason=" + reason);
        switch (state) {
            case DownloadManager.STATUS_PAUSED:
                switch (reason) {
                    // 暂停，等待继续
                    case DownloadManager.PAUSED_WAITING_TO_RETRY:
                        tipId = R.string.pause_msg_download_waiting_for_retry;
                        break;
                    // 等待可用网络
                    case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
                        //tipId = R.string.error_msg_download_waiting_for_network;
                        tipId = R.string.error_msg_download_queued_for_wifi;
                        break;
                    // 等待可用WIFI
                    case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
                        tipId = R.string.error_msg_download_queued_for_wifi;
                        break;
                }
                break;
            case DownloadManager.STATUS_FAILED:
                switch (reason) {
                    // 未发现存储卡
                    case DownloadManager.ERROR_DEVICE_NOT_FOUND:
                        tipId = R.string.error_msg_download_device_not_found;
                        break;
                    // 文件已存在
                    case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
                        tipId = R.string.error_msg_download_file_exists;
                        break;
                    // 存储卡已满
                    case DownloadManager.ERROR_INSUFFICIENT_SPACE:
                        tipId = R.string.error_msg_download_insufficient_space;
                        break;
                    // 未处理的HTTP错误
                    case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
                        tipId = R.string.error_msg_download_unknown_http_code;
                        break;
                    // 未知错误
                    case DownloadManager.ERROR_FILE_ERROR:
                        tipId = R.string.error_msg_download_file_not_found;
                        break;
                    default:
                        tipId = R.string.error_msg_download_unknown_error;
                        break;
                }
                break;
        }
        if (tipId != -1) {
            ToastUtils.showToast(String.format(context.getString(tipId), label));
        }
    }

    /**
     * 直接输入下载地址
     *
     * @param url 下载地址
     */
    public static void startInputDownload(String url) {
        if (Util.isHttpUrl(url))
            startDownload(url, false, "");
        else {
            ToastUtils.showToast(R.string.invalid_url);
        }

    }

    //TODO 所有下載參數改為VideoInfo
    public static void startDownload(String downloadUrl, boolean isDemoVideo, boolean isShowInList, int appId, String title) {
        try {
            // create a new download dir to replace the default download dir
            File downloadDir = DownloadManager.createDownloadDirIfNotExist();
            if (downloadDir == null) {
                ToastUtils.showToast(R.string.download_dir_not_found);
            } else if (isDemoVideo && new File(downloadDir, Constant.DEMO_VIDEO_NAME).exists()) {
                //如果已经下载了Demo不再重复下载
                LogUtils.d("demo exists");
                //do nothing
            } else {
                Uri srcUri = Uri.parse(downloadUrl);
                DownloadManager.Request request = new DownloadManager.Request(srcUri);
                if (!TextUtils.isEmpty(downloadUrl)) {
                    int index = downloadUrl.lastIndexOf("/");
                    String saveName = downloadUrl.substring(index, downloadUrl.length());
                    if (!TextUtils.isEmpty(title)) {
                        if (saveName.contains("."))
                            saveName = title + "." + saveName.split("\\.")[1];
                        request.setTitle(title);
                    } else {
                        request.setTitle(saveName);
                    }
                    String localUrl=downloadDir.getAbsolutePath() + "/" + saveName;
                    request.setDestinationInExternalPublicDir(DownloadManager.ROOT_DIR, saveName);
                    request.allowScanningByMediaScanner();
                    if (appId > 0)
                        request.setAppId(appId);
                    /*if (SharedPreferencesUtil.getInstance(VRApp.getInstance()).isWifiOnly()) {
                        if (NetworkUtil.isWifiConnected()) {
                            request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
                        } else if (NetworkUtil.isMobileDataConnected()) {
                            Activity activity = BaseActivity.getCurrentActivity();
                            if (activity != null)
                                ToastUtils.makeToastColorShow(activity, activity.findViewById(android.R.id.content), activity.getString(R.string.error_msg_download_wifi_only));
                            return;
                        }
                    }*/
                    request.setVisibleInDownloadsUi(false);
                    long downloadId = getDownloadManager().enqueue(request);
                    if (isShowInList) {
                        //通知首页更新下载列表
                        VideoInfo videoInfo = new VideoInfo();
                        videoInfo.setVideoId(downloadId);
                        videoInfo.setVideoPath(localUrl);
                        videoInfo.setVideoName(title);
                        videoInfo.setDemoVideo(isDemoVideo);
                        BusProvider.getInstance().post(videoInfo);
                    } else if (downloadUrl.endsWith(Constant.APK)) {
                        SharedPreferencesUtil.getInstance(VRApp.getInstance()).setVersionUpdateDownloadID(downloadId);
                    }
                }
            }

        } catch (IllegalArgumentException e) {

        }

    }

    public static void startDownload(String url, boolean isDemoVideo, String videoName) {
        startDownload(url, isDemoVideo, true, 0, videoName);
    }

    public static void startDownloadDiscoverVideo(String url, int appId, String videoName) {
        startDownload(url, false, true, appId, videoName);
    }

    /**
     * 添加新的wifi传输视频到下载列表
     *
     * @param videoName
     * @param videoPath
     */
    public static void addNewTransferVideoTask(final String videoName, final String videoPath) {
        Single.create(new Single.OnSubscribe<VideoInfo>() {
            @Override
            public void call(SingleSubscriber<? super VideoInfo> singleSubscriber) {

                VideoInfo videoInfo = new VideoInfo();
//                videoInfo.setVideoId(-1);//不是下载的文件的id默认为-1
                videoInfo.setVideoName(videoName);
                videoInfo.lintToMeida(VRApp.getContext(), videoPath);
                videoInfo.setVideoPath(FileUtil.getFilePathWithFile(videoPath));
                videoInfo.setVideoSize(FileUtil.getFileSize(videoPath));
                videoInfo.setDownloadedSize(videoInfo.getVideoSize());
                videoInfo.setDownloadByDownloadManager(false);
                videoInfo.setDownloadedPercent(100);
                videoInfo.setDownloadState(DownloadManager.STATUS_SUCCESSFUL);
                MediaMetadataRetriever mMediaRetriever = new MediaMetadataRetriever();
                try {
                    mMediaRetriever.setDataSource(videoPath);
                    String duration = mMediaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);

                    if (duration != null && TextUtils.isDigitsOnly(duration)) {
                        videoInfo.setDuration(Long.parseLong(duration));
                        String formatDuration = Util.getDuration(videoInfo.getDuration()); // 播放时长单位为毫秒
                        videoInfo.setFormatDuration(formatDuration);
                    }
                } catch (Exception e) {
                    LogUtils.e("format duration exception");
                }
                singleSubscriber.onSuccess(videoInfo);
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new SingleSubscriber<VideoInfo>() {
            @Override
            public void onSuccess(VideoInfo videoInfo) {
                BusProvider.getInstance().post(videoInfo);
            }

            @Override
            public void onError(Throwable error) {

            }
        });

    }


    /**
     * 判断是否此url视频已经下载了
     *
     * @param url 下载地址
     * @return
     */
    public static boolean isFileExist(String url) {
        int queryFilter = DownloadManager.STATUS_PENDING
                | DownloadManager.STATUS_RUNNING
                | DownloadManager.STATUS_PAUSED
                | DownloadManager.STATUS_FAILED;
        DownloadManager.Query query = new DownloadManager.Query().setFilterByStatus(queryFilter);
        boolean result = false;
        Cursor cursor = getDownloadManager().query(query);
        if (cursor == null || cursor.isClosed())
            return false;
        int taskUri = cursor.getColumnIndex(DownloadManager.COLUMN_URI);
        while (cursor.moveToNext()) {
            if (cursor.getString(taskUri).equals(url)) {
                result = true;
                break;
            }
        }
        if (!cursor.isClosed())
            cursor.close();
        return result;
    }


    /**
     * 根据下载任务的status获取当前该状态的任务个数
     *
     * @param status 任务的状态
     * @return
     */
    public static int getApkCountByStatus(int status) {
        int count = 0;
        DownloadManager.Query downloadQuery = new DownloadManager.Query();
        downloadQuery.setFilterByStatus(status);
        DownloadManager mDownloadManager = DownloadHelper
                .getDownloadManager();
        if (mDownloadManager == null)
            return count;

        Cursor cursor = mDownloadManager.query(downloadQuery);
        if (cursor == null || cursor.isClosed())
            return count;

        count = cursor.getCount();
        cursor.close();
        return count;
    }

    /**
     * 对下载完成的任务或者下载失败的任务重新下载
     *
     * @param context
     * @param ids
     * @return
     */
    public synchronized static boolean restartDownload(Context context, long... ids) {
        if (checkWifiOnly(context)) {
            try {
                getDownloadManager().restartDownload(ids);
                return true;
            } catch (IllegalArgumentException ex) {
                LogUtils.e(ex.getMessage());
            }
        }
        return false;
    }

    /**
     * 检测是否只在Wifi模式下进行下载，如果是且Wifi未开，则弹出提示并返回false，否则true
     *
     * @param context
     * @return
     */
    private static boolean checkWifiOnly(Context context) {
        if (SharedPreferencesUtil.getInstance(context).isWifiOnly() && !NetworkUtil.isWifiConnected()) {
            //ToastUtil.showToast(context.getResources().getString(R.string.error_msg_download_wifi_only));
            return false;
        }
        return true;
    }

    /**
     * 继续下载
     *
     * @param context
     * @param ids
     * @return
     */
    public synchronized static boolean resumeDownload(Context context, long... ids) {
        if (checkWifiOnly(context)) {
            try {
                getDownloadManager().resumeDownload(ids);
                return true;
            } catch (IllegalArgumentException ex) {
                LogUtils.e(ex.getMessage());
            }
        }
        return false;
    }

    /**
     * 取消相应的下载任务
     *
     * @param context
     * @param ids
     * @return
     */
    public synchronized static int cancelDownload(Context context, long... ids) {
        try {
            return getDownloadManager().remove(ids);
        } catch (IllegalArgumentException ex) {
            LogUtils.e(ex.getMessage());
            return 0;
        }
    }

    /**
     * Manually pause the download task
     *
     * @param context
     * @param ids
     * @return
     */
    public synchronized static boolean pauseDownload(Context context, long... ids) {
        try {
            getDownloadManager().pauseDownload(ids);
        } catch (IllegalArgumentException ex) {
            LogUtils.e(ex.getMessage());
            return false;
        }
        return true;
    }

    public static String getVideoPath(long videoId) {
        List<VideoInfo>list=new Select().from(VideoInfo.class).where(VideoInfo.COLUMN_VIDEO_ID+" = ?",videoId).execute();
        if(list!=null&&!list.isEmpty())
            return list.get(0).getVideoPath();
        return null;
    }
}
